﻿using Quartz.Impl.Matchers;
using Quartz;
using System.Text.Json;
using System.Text.Encodings.Web;

namespace 微信机器人服务.Quartz
{
    /// <summary>
    /// 
    /// </summary>
    public class QuartzJobsFactory : IQuartzJobsFactory
    {
        private readonly ILogger<QuartzJobsFactory> _logger;
        private readonly IScheduler _scheduler;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="scheduler"></param>
        public QuartzJobsFactory(ILogger<QuartzJobsFactory> logger, IScheduler scheduler)
        {
            _logger = logger;
            _scheduler = scheduler;
        }
        /// <summary>
        /// 检查存在
        /// </summary>
        /// <param name="jobKey"></param>
        /// <returns></returns>
        public async Task<bool> CheckExistsAsync(JobKey jobKey)
        {
            return await _scheduler.CheckExists(jobKey);
        }
        /// <summary>
        /// 检查存在
        /// </summary>
        /// <param name="JobName"></param>
        /// <returns></returns>
        public async Task<bool> CheckExistsAsync(string JobName)
        {
            var jobkey = await GetJobKeyByNameAsync(JobName);
            if (jobkey != null)
            {
                return await CheckExistsAsync(jobkey);
            }
            else
                return false;
        }
        /// <summary>
        /// 创建工作
        /// </summary>
        /// <param name="JobName"></param>
        /// <param name="timeSpan"></param>
        /// <param name="repeatTime"></param>
        /// <returns></returns>
        public async Task<bool> CreateJobAsync(string JobName, TimeSpan timeSpan, int repeatTime)
        {
            var jobkey = await GetJobKeyByNameAsync(JobName);
            if (jobkey != null)
            {
                _logger.LogError("该Job已经创建：" + JobName);
                return false;
            }
            else if (repeatTime >= -1)
            {
                var type = GetClassExtendOfIJobByName(JobName);
                IJobDetail job = JobBuilder.Create(type).WithIdentity(JobName).Build();

                if (repeatTime == -1)
                {
                    ITrigger trigger = TriggerBuilder.Create().WithIdentity(JobName).StartNow().WithSimpleSchedule(x => x.WithInterval(timeSpan).RepeatForever()).Build();
                    await _scheduler.ScheduleJob(job, trigger);

                }
                else
                {
                    ITrigger trigger = TriggerBuilder.Create().WithIdentity(JobName).StartNow().WithSimpleSchedule(x => x.WithInterval(timeSpan).WithRepeatCount(0)).Build();
                    await _scheduler.ScheduleJob(job, trigger);

                }

                return true;
            }
            return false;
        }


        /// <summary>
        /// 创建工作
        /// </summary>
        /// <param name="JobName"></param>
        /// <param name="cronExpression">"0 0 * * * ?" 整点</param>
        /// <param name="keyValuePair">传递参数</param>
        /// <returns></returns>
        public async Task<bool> CreateJobAsync(string JobName, string cronExpression, KeyValuePair<string, object> keyValuePair)
        {
            var jobkey = await GetJobKeyByNameAsync(JobName);
            if (jobkey != null)
            {
                _logger.LogError("该Job已经创建：" + JobName);
                return false;
            }
            else
            {
                var type = GetClassExtendOfIJobByName(JobName);
                IJobDetail job = JobBuilder.Create(type).WithIdentity(JobName)
                    .SetJobData(new JobDataMap() { keyValuePair }).Build();

                ITrigger trigger = TriggerBuilder.Create().WithIdentity(JobName).StartNow()//立即启动
                    .WithCronSchedule(cronExpression)//整点运行
                    .Build();
                await _scheduler.ScheduleJob(job, trigger);
                return true;
            }
        }
        /// <summary>
        /// 创建工作
        /// </summary>
        /// <param name="jobName"></param>
        /// <param name="cronExpression">"0 0 * * * ?" 整点</param>
        /// <returns></returns>
        public async Task<bool> CreateJobAsync(string jobName, string cronExpression)
        {
            var jobkey = await GetJobKeyByNameAsync(jobName);
            if (jobkey != null)
            {
                _logger.LogError("该Job已经创建：" + jobName);
                return false;
            }
            else
            {
                var type = GetClassExtendOfIJobByName(jobName);
                IJobDetail job = JobBuilder.Create(type).WithIdentity(jobName)
                    .Build();

                ITrigger trigger = TriggerBuilder.Create().WithIdentity(jobName).StartNow()//立即启动
                    .WithCronSchedule(cronExpression)//整点运行
                    .Build();

                await _scheduler.ScheduleJob(job, trigger);
                return true;
            }
        }

        /// <summary>
        /// 创建只执行一次的工作
        /// </summary>
        /// <param name="jobName"></param>
        /// <param name="runTime">任务执行的具体时间</param>
        /// <returns></returns>
        public async Task<bool> CreateJobAsync(string jobName, DateTimeOffset runTime)
        {
            // 使用 GUID 生成唯一的 JobKey
            var uniqueJobName = $"{jobName}_{Guid.NewGuid()}";
            var jobKey = new JobKey(uniqueJobName);
            // 获取实现了 IJob 的类型
            var type = GetClassExtendOfIJobByName(jobName);

            // 定义作业
            IJobDetail job = JobBuilder.Create(type)
                .WithIdentity(jobKey)
                .Build();

            // 定义触发器，仅在指定时间执行一次
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(uniqueJobName)
                .StartAt(runTime) // 任务执行的具体时间
                .Build();

            // 使用调度器安排任务
            await _scheduler.ScheduleJob(job, trigger);
            return true;
        }
        JsonSerializerOptions options = new JsonSerializerOptions
        {
            WriteIndented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
        };
        /// <summary>
        /// 创建只执行一次的工作，并向作业传递参数。
        /// </summary>
        /// <param name="jobName"></param>
        /// <param name="runTime">任务执行的具体时间</param>
        /// <param name="jobParams">作业参数，将作为键值对传递</param>
        /// <returns></returns>
        public async Task<bool> CreateJobAsync(string jobName, DateTimeOffset runTime, IDictionary<string, object> jobParams)
        {
            // 使用 GUID 生成唯一的 JobKey
            var uniqueJobName = $"{jobName}_{Guid.NewGuid()}";
           
            var jobKey = new JobKey(uniqueJobName);
            _logger.LogInformation($"使用 GUID 生成唯一的 JobKey {uniqueJobName} {JsonSerializer.Serialize(jobKey, options)}");
            // 获取实现了 IJob 的类型
            var type = GetClassExtendOfIJobByName(jobName);

            // 定义作业，并传递参数
            IJobDetail job = JobBuilder.Create(type)
                .WithIdentity(jobKey)
                .UsingJobData(new JobDataMap(jobParams)) // 传递参数到作业中
                .Build();
            _logger.LogInformation($"定义作业，并传递参数 参数： {JsonSerializer.Serialize(jobParams, options)}");
            // 定义触发器，仅在指定时间执行一次
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(uniqueJobName)
                .StartAt(runTime) // 任务执行的具体时间
                .Build();
            _logger.LogInformation($"定义触发器，仅在指定时间执行一次 {JsonSerializer.Serialize(trigger, options)} 参数：DateTimeOffset： {runTime.LocalDateTime}");
            // 使用调度器安排任务
          var dateTimeOffset= await _scheduler.ScheduleJob(job, trigger);
            _logger.LogInformation($"使用调度器安排任务 返回：DateTimeOffset： {dateTimeOffset.LocalDateTime}");
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="jobName"></param>
        /// <param name="millisecond">毫秒</param>
        /// <returns></returns>
        public async Task<bool> CreateJobAsync(string jobName, int millisecond)
        {
            var jobkey = await GetJobKeyByNameAsync(jobName);
            if (jobkey != null)
            {
                _logger.LogError("该Job已经创建：" + jobName);
                return false;
            }
            else
            {
                var type = GetClassExtendOfIJobByName(jobName);
                IJobDetail job = JobBuilder.Create(type).WithIdentity(jobName)
                    .Build();

                ITrigger trigger = TriggerBuilder.Create().WithIdentity(jobName).StartNow()//立即启动
                    .WithSimpleSchedule(e=>e.WithInterval(TimeSpan.FromMilliseconds(millisecond)).RepeatForever())
                    .Build();

                await _scheduler.ScheduleJob(job, trigger);
                return true;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="JobName"></param>
        /// <param name="timeSpan"></param>
        /// <param name="repeatTime"></param>
        /// <param name="keyValuePair"></param>
        /// <returns></returns>
        public async Task<bool> CreateJobAsync(string JobName, TimeSpan timeSpan, int repeatTime, KeyValuePair<string, object> keyValuePair)
        {
            var jobkey = await GetJobKeyByNameAsync(JobName);
            if (jobkey != null)
            {
                _logger.LogError("该Job已经创建：" + JobName);
                return false;
            }
            else if (repeatTime >= -1)
            {
                var type = GetClassExtendOfIJobByName(JobName);
                IJobDetail job = JobBuilder.Create(type).WithIdentity(JobName).SetJobData(new JobDataMap() {
                                keyValuePair
                            }).Build();

                if (repeatTime == -1)
                {
                    ITrigger trigger = TriggerBuilder.Create().WithIdentity(JobName).StartNow().WithSimpleSchedule(x => x.WithInterval(timeSpan).RepeatForever()).Build();
                    await _scheduler.ScheduleJob(job, trigger);

                }
                else
                {
                    ITrigger trigger = TriggerBuilder.Create().WithIdentity(JobName).StartNow().WithSimpleSchedule(x => x.WithInterval(timeSpan).WithRepeatCount(0)).Build();
                    await _scheduler.ScheduleJob(job, trigger);

                }

                return true;
            }
            return false;
        }
        /// <inheritdoc/>
        public IEnumerable<string> GetAllAvailableJobName()
        {
            var typesExtendOfIJob = GetClassExtendOfIJob();
            return typesExtendOfIJob.Select(t => t.Name);
        }
        /// <inheritdoc/>
        public IEnumerable<Type> GetClassExtendOfIJob()
        {
            var types = AppDomain.CurrentDomain.GetAssemblies();
            var typesExtendOfIJob = types.SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob))));
            return typesExtendOfIJob;
        }
        /// <inheritdoc/>
        public Type GetClassExtendOfIJobByName(string jobName)
        {

            var jobObject = GetClassExtendOfIJob();
            var result = jobObject.Where(t => t.Name.Contains(jobName)).FirstOrDefault();
            return result;
        }
        /// <inheritdoc/>
        public async Task<JobKey> GetJobKeyByNameAsync(string jobName)
        {
            var match = GroupMatcher<JobKey>.AnyGroup();
            var jobkeys = await _scheduler.GetJobKeys(match);
            return jobkeys.Where(t => t.Name.Contains(jobName)).FirstOrDefault()!;
        }
        /// <inheritdoc/>
        public async Task<TriggerKey> GetTriggerKeyByNameAsync(string triggerKeyName)
        {
            var match = GroupMatcher<TriggerKey>.AnyGroup();
            var triggerKeys = await _scheduler.GetTriggerKeys(match);
            return triggerKeys.Where(t => t.Name.Contains(triggerKeyName)).FirstOrDefault()!;
        }
        /// <inheritdoc/>
        public async Task<IReadOnlyCollection<ITrigger>> GetTriggersOfJobAsync(JobKey jobKey)
        {
            return await _scheduler.GetTriggersOfJob(jobKey);
        }
        /// <inheritdoc/>
        public async Task<IReadOnlyCollection<ITrigger>?> GetTriggersOfJobAsync(string jobName)
        {
            var jobKey = await GetJobKeyByNameAsync(jobName);
            return jobKey == null ? null : await _scheduler.GetTriggersOfJob(jobKey!);
        }
        /// <inheritdoc/>
        public virtual Task<TriggerState> GetTriggerStateAsync(TriggerKey triggerKey)
        {
            return _scheduler.GetTriggerState(triggerKey);
        }
        /// <inheritdoc/>
        public async Task PauseAllAsync()
        {
            await _scheduler.PauseAll();
        }
        /// <inheritdoc/>
        public async Task PauseJobAsync(JobKey jobKey)
        {
            await _scheduler.PauseJob(jobKey);
        }
        /// <inheritdoc/>
        public async Task PauseJobAsync(string jobName)
        {
            var jobKey = await GetJobKeyByNameAsync(jobName);
            if (jobKey != null)
            {
                await PauseJobAsync(jobKey);
            }
        }
        /// <inheritdoc/>
        public async Task PauseTriggerAsync(string triggerKeyName)
        {
            var triggerKey = await GetTriggerKeyByNameAsync(triggerKeyName);
            await _scheduler.PauseTrigger(triggerKey);
        }
        /// <inheritdoc/>
        public async Task PauseTriggerAsync(TriggerKey triggerKey)
        {
            await _scheduler.PauseTrigger(triggerKey);
        }
        /// <inheritdoc/>
        public async Task ResumeAllAsync()
        {
            await _scheduler.ResumeAll();
        }
        /// <inheritdoc/>
        public async Task ResumeJobAsync(string jobName)
        {
            var jobKey = await GetJobKeyByNameAsync(jobName);
            if (jobKey != null)
            {
                await ResumeJobAsync(jobKey);
            }
        }
        /// <inheritdoc/>
        public async Task ResumeJobAsync(JobKey jobKey)
        {
            await _scheduler.ResumeJob(jobKey);
        }
        /// <inheritdoc/>
        public async Task ResumeTriggerAsync(TriggerKey triggerKey)
        {
            await _scheduler.ResumeTrigger(triggerKey);
        }
        /// <inheritdoc/>
        public async Task ResumeTriggerAsync(string triggerKeyName)
        {
            var triggerKey = await GetTriggerKeyByNameAsync(triggerKeyName);

            await _scheduler.ResumeTrigger(triggerKey);
        }
    }
}
